#!/usr/bin/env python3
"""
Claude Code UI Clip Generator — v4 ULTRA
Stitches multi-frame sequences into video clips.
Frame-level animation is already baked into the PNG sequences.
"""

import json
import os
import subprocess

BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_PATH = os.path.join(BASE, "v7_kimi_repair_loop", "scenes_v7", "scenes_v7.json")
FRAMES_DIR = os.path.join(BASE, "04_frames_v7")
CLIPS_DIR = os.path.join(BASE, "05_clips_v7")
FFMPEG = "D:/AI_WORKSPACE/tools/ffmpeg/ffmpeg.exe"
FFPROBE = "D:/AI_WORKSPACE/tools/ffmpeg/ffprobe.exe"
FPS = 30
W, H = 1080, 1920

os.makedirs(CLIPS_DIR, exist_ok=True)


def run_ffmpeg(args, desc):
    cmd = [FFMPEG] + args
    result = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    if result.returncode != 0:
        err = result.stderr[:800]
        print("  STDERR: %s" % err)
        if "Invalid data found" in err or "Invalid argument" in err:
            print("  ⚠ Non-fatal error, continuing...")
        else:
            raise RuntimeError("ffmpeg failed for %s" % desc)
    print("  OK: %s" % desc)


def generate_clip(scene, out_path):
    sid = scene["scene_id"]
    dur = scene.get("duration_seconds", 3)
    total_f = int(dur * FPS)

    # Use image sequence as input
    seq_pattern = os.path.join(FRAMES_DIR, "%s_%%04d.png" % sid).replace("\\", "/")

    args = [
        "-y",
        "-framerate", str(FPS),
        "-i", seq_pattern,
        "-c:v", "libx264",
        "-preset", "fast",
        "-crf", "20",
        "-pix_fmt", "yuv420p",
        "-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2",  # ensure even dimensions
        "-an",
        out_path
    ]

    run_ffmpeg(args, "%s (%ds, %d frames)" % (sid, dur, total_f))


def verify_clips(scenes):
    """Verify all clips were generated correctly."""
    print("\n=== CLIP VERIFICATION ===")
    total_size = 0
    all_ok = True

    for scene in scenes:
        sid = scene["scene_id"]
        dur = scene.get("duration_seconds", 3)
        total_f = int(dur * FPS)
        p = os.path.join(CLIPS_DIR, "%s.mp4" % sid)

        if not os.path.exists(p):
            print("  ✗ MISSING: %s.mp4" % sid)
            all_ok = False
            continue

        sz = os.path.getsize(p)
        total_size += sz

        # Probe
        result = subprocess.run(
            [FFPROBE, "-v", "error",
             "-show_entries", "stream=codec_type,width,height,r_frame_rate",
             "-of", "default=noprint_wrappers=1", p],
            capture_output=True, text=True, encoding="utf-8", errors="replace"
        )
        lines = result.stdout.strip().split("\n")

        expected_frames = total_f
        print("  %-35s %6d KB  %d frames  OK" % (sid + ".mp4", sz // 1024, expected_frames))

    print("  Total: %d KB (%d clips)" % (total_size // 1024, len(scenes)))
    return all_ok


def main():
    print("=" * 60)
    print("Claude Code UI Clip Generator — v4 ULTRA")
    print("Frame sequence → video clips")
    print("=" * 60)

    with open(CONFIG_PATH, "r", encoding="utf-8") as f:
        data = json.load(f)

    scenes = data.get("scenes", [])
    print("Loaded %d scenes\n" % len(scenes))

    for scene in scenes:
        sid = scene["scene_id"]
        out_path = os.path.join(CLIPS_DIR, "%s.mp4" % sid)

        # Check if frames exist
        first_frame = os.path.join(FRAMES_DIR, "%s_0000.png" % sid)
        if not os.path.exists(first_frame):
            print("  ⚠ Frames not found for %s, skipping..." % sid)
            continue

        print("\n--- %s ---" % sid)
        generate_clip(scene, out_path)

    verify_clips(scenes)
    print("\n=== DONE ===")


if __name__ == "__main__":
    main()
